package com.zzyl.nursing.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zzyl.nursing.domain.Device;
import com.zzyl.nursing.domain.DeviceData;
import com.zzyl.nursing.domain.IotMsgNotifyData;
import com.zzyl.nursing.mapper.DeviceDataMapper;
import com.zzyl.nursing.mapper.DeviceMapper;
import com.zzyl.nursing.service.IDeviceDataService;
import com.zzyl.nursing.vo.DeviceDataStatisticsVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 设备数据Service业务层处理
 *
 * @author ruoyi
 * @date 2025-09-27
 */
@Service
public class DeviceDataServiceImpl extends ServiceImpl<DeviceDataMapper, DeviceData> implements IDeviceDataService
{
    @Autowired
    DeviceDataMapper deviceDataMapper;

    @Autowired
    private DeviceMapper deviceMapper;

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    /**
     * 查询设备数据
     *
     * @param id 设备数据主键
     * @return 设备数据
     */
    @Override
    public DeviceData selectDeviceDataById(Long id)
    {
        return getById(id);
    }

    /**
     * 查询设备数据列表
     *
     * @param deviceData 设备数据
     * @return 设备数据
     */
    @Override
    public List<DeviceData> selectDeviceDataList(DeviceData deviceData)
    {
        return deviceDataMapper.selectDeviceDataList(deviceData);
    }

    /**
     * 新增设备数据
     *
     * @param deviceData 设备数据
     * @return 结果
     */
    @Override
    public int insertDeviceData(DeviceData deviceData)
    {
        return save(deviceData) ? 1 : 0;
    }

    /**
     * 修改设备数据
     *
     * @param deviceData 设备数据
     * @return 结果
     */
    @Override
    public int updateDeviceData(DeviceData deviceData)
    {
        return updateById(deviceData) ? 1 : 0;
    }

    /**
     * 批量删除设备数据
     *
     * @param ids 需要删除的设备数据主键
     * @return 结果
     */
    @Override
    public int deleteDeviceDataByIds(Long[] ids)
    {
        return removeByIds(Arrays.asList(ids)) ? 1 : 0;
    }

    /**
     * 删除设备数据信息
     *
     * @param id 设备数据主键
     * @return 结果
     */
    @Override
    public int deleteDeviceDataById(Long id)
    {
        return removeById(id) ? 1 : 0;
    }

    @Override
    public void insertAmqpData(String contentStr) {
        JSONObject jsonObject = JSONUtil.parseObj(contentStr);
        Object object = jsonObject.get("notify_data");

        //1.解析数据
        IotMsgNotifyData iotMsgNotifyData = BeanUtil.toBean(object, IotMsgNotifyData.class);
        //2.设备id 查询数据库
        String deviceId = iotMsgNotifyData.getHeader().getDeviceId();
        Device device = deviceMapper.selectOne(new QueryWrapper<Device>().eq("iot_id", deviceId));
        if(device != null){
            throw new RuntimeException("设备不存在");
        }
        //3.数据对象进行分析，获取properties map 数据循环插入到数据库
        iotMsgNotifyData.getBody().getServices().forEach(service -> {

            List<DeviceData> deviceDataList = new ArrayList<>();

            service.getProperties().forEach((key,value)->{

                DeviceData deviceData = BeanUtil.toBean(device, DeviceData.class);
                deviceData.setIotId(deviceId);
                deviceData.setAccessLocation(device.getBindingLocation());
                deviceData.setFunctionId(key);
                deviceData.setDataValue(String.valueOf(value));
                //处理上报时间日期
                LocalDateTime eventTime =  LocalDateTimeUtil.parse(service.getEventTime(), "yyyyMMdd'T'HHmmss'Z'");
                //日期时区转换
                LocalDateTime alarmTime = eventTime.atZone(ZoneId.from(ZoneOffset.UTC))
                        .withZoneSameInstant(ZoneId.of("Asia/Shanghai"))
                        .toLocalDateTime();
                deviceData.setAlarmTime(alarmTime);
                deviceData.setId(null);
                deviceDataList.add(deviceData);
            });
           this.saveBatch(deviceDataList);
           //把插入到数据库的数据，同时放入到redis 中
            redisTemplate.opsForHash().put("iot:device_data", deviceId, JSONUtil.toJsonStr(deviceDataList));
        });

    }

     /**
     * 根据指定的时间范围查询设备按小时统计的数据列表
     *
     * @param iotId 设备唯一标识符
     * @param startTime 查询开始时间戳（毫秒）
     * @param endTime 查询结束时间戳（毫秒）
     * @param functionId 功能点标识符
     * @return 返回按小时统计的设备数据列表，包含每个小时对应的数据值
     */
    @Override
    public List<DeviceDataStatisticsVo> queryDeviceDataListByDay(String iotId, Long startTime, Long endTime, String functionId) {
        // 将时间戳转换为LocalDateTime
        LocalDateTime startDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(startTime), ZoneId.systemDefault());
        LocalDateTime endDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(endTime), ZoneId.systemDefault());

        // 查询指定时间范围内的设备数据
        List<DeviceData> deviceDataList = list(new QueryWrapper<DeviceData>()
                .eq("iot_id", iotId)
                .eq("function_id", functionId)
                .ge("alarm_time", startDateTime)
                .le("alarm_time", endDateTime));

        // 初始化24小时统计数据
        Map<Integer, DeviceDataStatisticsVo> statisticsMap = new LinkedHashMap<>();
        for (int i = 0; i < 24; i++) {
            String hour = String.format("%02d:00", i);
            statisticsMap.put(i, new DeviceDataStatisticsVo(hour, 0.0));
        }

        // 按小时统计数据并更新每小时的数据值
        deviceDataList.forEach(data -> {
            LocalDateTime alarmTime = data.getAlarmTime();
            int hour = alarmTime.getHour();
            Double currentValue = Double.valueOf(data.getDataValue());

            // 更新该小时的数据值（当前实现为保留最新值）
            DeviceDataStatisticsVo stat = statisticsMap.get(hour);
            if (stat.getDataValue() == 0.0) {
                stat.setDataValue(currentValue);
            } else {
                // 如果需要计算平均值可以使用以下逻辑
                // stat.setDataValue((stat.getDataValue() + currentValue) / 2);
                // 或者保留最新值
                stat.setDataValue(currentValue);
            }
        });

        return new ArrayList<>(statisticsMap.values());
    }

        /**
     * 按周统计查询指标数据
     * @param iotId 设备Id，用于筛选特定设备的数据
     * @param startTime 开始时间的时间戳（毫秒），用于限定查询起始时间
     * @param endTime 结束时间的时间戳（毫秒），用于限定查询结束时间
     * @param functionId 功能ID，用于筛选特定功能类型的数据
     * @return 返回按日期统计后的设备数据列表，每个元素包含日期和对应的统计数据
     */
    @Override
    public List<DeviceDataStatisticsVo> queryDeviceDataListByWeek(String iotId, Long startTime, Long endTime, String functionId) {
        // 将输入的时间戳转换为系统时区的LocalDateTime对象，便于后续处理
        LocalDateTime startDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(startTime), ZoneId.systemDefault());
        LocalDateTime endDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(endTime), ZoneId.systemDefault());

        // 根据设备ID、功能ID以及时间范围查询符合条件的所有设备数据记录
        List<DeviceData> deviceDataList = list(new QueryWrapper<DeviceData>()
                .eq("iot_id", iotId)
                .eq("function_id", functionId)
                .ge("alarm_time", startDateTime)
                .le("alarm_time", endDateTime));

        // 按照日期（忽略具体时间）对查询到的数据进行分组，方便后续按天统计
        Map<LocalDate, List<DeviceData>> groupedByDate = deviceDataList.stream()
                .collect(Collectors.groupingBy(data -> data.getAlarmTime().toLocalDate()));

        // 初始化结果列表，用于存储每天的统计数据
        List<DeviceDataStatisticsVo> result = new ArrayList<>();

        // 遍历从开始日期到结束日期之间的每一天
        LocalDate currentDate = startDateTime.toLocalDate();
        LocalDate endDate = endDateTime.toLocalDate();

        while (!currentDate.isAfter(endDate)) {
            // 格式化当前日期为"MM.dd"格式字符串作为展示用日期字段
            String dateStr = currentDate.format(DateTimeFormatter.ofPattern("MM.dd"));

            // 获取当天对应的数据列表，若无则使用空列表避免空指针异常
            List<DeviceData> dailyData = groupedByDate.getOrDefault(currentDate, Collections.emptyList());

            // 当前实现中以数据条数作为统计值，可根据业务需求替换为其他聚合逻辑
            double dataValue = dailyData.size();
            result.add(new DeviceDataStatisticsVo(dateStr, dataValue));

            // 移动至下一天继续处理
            currentDate = currentDate.plusDays(1);
        }

        return result;
    }



}
